package cn.com.netedge.iot.frontend.comm.utils;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.util.FileSize;
import cn.com.netedge.iot.common.enums.MessageDirectEnum;
import cn.com.netedge.iot.common.utils.DateUtil;
import cn.com.netedge.iot.common.utils.ProtocolUtils;
import cn.com.netedge.iot.common.utils.StringUtil;
import cn.com.netedge.iot.frontend.comm.service.DeviceService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class DeviceLogUtil {
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(DeviceLogUtil.class);
    public static DeviceLogUtil deviceLogger;

    public static Map<String, Logger> loggerMap = new HashMap<>();
    public static Map<String, Long> loggerLiveMap = new HashMap<>();

    @Autowired
    private DeviceService deviceService;

    @PostConstruct
    public void init() {
        deviceLogger = this;
    }

    public static Logger getLogger(String deviceNumber) {
        loggerLiveMap.put(deviceNumber, System.currentTimeMillis());
        Logger logger = loggerMap.get(deviceNumber);
        if (logger != null) {
            return logger;
        }
        synchronized (DeviceLogUtil.class) {
            logger = loggerMap.get(deviceNumber);
            if (logger != null) {
                return logger;
            }
            logger = build(deviceNumber);
            loggerMap.put(deviceNumber, logger);
        }
        return logger;
    }

    private static Logger build(String deviceNumber) {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        Logger logger = context.getLogger(deviceNumber);
        logger.setAdditive(false);
        RollingFileAppender appender = new RollingFileAppender();
        appender.setContext(context);
        appender.setName(deviceNumber);
        // 判断文件已经存在，先重命名
        String filePath = "logs" + File.separator + "device-logs" + File.separator + "rtu-" + deviceNumber + ".log";
        int deviceNumberSize = deviceNumber.length();
        File file = new File(filePath);
        if(file.exists()) {
            Date now = new Date();
            String dest = filePath + "." + DateUtil.DateToStr(now, DateUtil.TIME_LONG_12) + ".zip";
            ZipUtil.toZipFile(filePath, dest);
            file.delete();
        }
        appender.setFile(filePath);
        appender.setAppend(true);
        appender.setPrudent(false);

        FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
        rollingPolicy.setMinIndex(1);
        rollingPolicy.setMaxIndex(5);
        rollingPolicy.setFileNamePattern("logs" + File.separator + "device-logs" + File.separator + "rtu-" + deviceNumber + "-%i.log.zip");
        rollingPolicy.setParent(appender);
        rollingPolicy.setContext(context);
        rollingPolicy.start();

        SizeBasedTriggeringPolicy triggeringPolicy = new SizeBasedTriggeringPolicy();
        triggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB"));
        triggeringPolicy.setContext(context);
        triggeringPolicy.start();

        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(context);
        encoder.setPattern("%d{yyyy-MM-dd/HH:mm:ss.SSS}| %logger{50} - %m%n");
        encoder.start();

        appender.setRollingPolicy(rollingPolicy);
        appender.setTriggeringPolicy(triggeringPolicy);
        appender.setEncoder(encoder);
        appender.start();
        logger.addAppender(appender);
        logger.setLevel(Level.TRACE);
        return logger;
    }

    private Logger getDeviceLogger(String deviceNumber, int deviceType) {
        if (StringUtil.isEmpty(deviceNumber)) {
            logger.error("record message error. deviceNumber is null or blank.");
            return null;
        }

        if (deviceService.getDeviceInfo(deviceNumber, deviceType) == null) {
            logger.error("record message error. deviceNumber:{} deviceType:{} 's device info not exists.", deviceNumber, deviceType);
            return null;
        }

        return getLogger(deviceNumber);
    }

    public void logMessage(String deviceNumber, int deviceType, MessageDirectEnum direct, byte[] buf) {
        Logger rtuLogger = getDeviceLogger(deviceNumber, deviceType);
        if (rtuLogger == null) {
            logger.error("record message error. rtu logger is null.");
            return;
        }

        if (MessageDirectEnum.DOWN.equals(direct)) {
            rtuLogger.debug("send:" + ProtocolUtils.printMsg(0, buf.length, buf));
        } else if (MessageDirectEnum.DELAY_DOWN.equals(direct)) {
            rtuLogger.debug("send:" + ProtocolUtils.printMsg(0, buf.length, buf));
        } else if (MessageDirectEnum.DECRYPT_BEFORE.equals(direct)) {
            rtuLogger.debug("decrypt_before:" + ProtocolUtils.printMsg(0, buf.length, buf));
        } else if (MessageDirectEnum.DECRYPT_AFTER.equals(direct)) {
            rtuLogger.debug("decrypt_after:" + ProtocolUtils.printMsg(0, buf.length, buf));
        } else {
            rtuLogger.debug("recieve: " + ProtocolUtils.printMsg(0, buf.length, buf));
        }
    }

    public void logAbnormalMessage(String deviceNumber, int deviceType, MessageDirectEnum direct, byte[] buf) {
        Logger rtuLogger = getLogger( deviceNumber);
        if (rtuLogger == null) {
            logger.error("record message error. rtu logger is null.");
            return;
        }

        if (MessageDirectEnum.DOWN.equals(direct)) {
            rtuLogger.debug("send:" + ProtocolUtils.printMsg(0, buf.length, buf));
        } else if (MessageDirectEnum.DELAY_DOWN.equals(direct)) {
            rtuLogger.debug("delay_send:" + ProtocolUtils.printMsg(0, buf.length, buf));
        } else {
            rtuLogger.debug("recieve: " + ProtocolUtils.printMsg(0, buf.length, buf));
        }
    }

}

